class Histogram:
    # 类属性
    version = "1.0"
    total_histograms = 0

    def __init__(self, n):
        """构造函数：初始化长度为n的直方图"""
        if not isinstance(n, int) or n <= 0:
            raise ValueError("n必须是正整数")

        # 私有属性
        self.__bins = [0] * n  # 直方图数据
        self.__size = n

        # 更新类属性
        Histogram.total_histograms += 1

    def addDataPoint(self, i):
        """增加一个数据点"""
        if not self._is_valid_index(i):
            raise ValueError(f"数据点{i}超出范围[0, {self.__size - 1}]")

        self.__bins[i] += 1

    # 属性封装
    @property
    def data(self):
        """直方图数据的只读属性"""
        return self.__bins.copy()  # 返回副本保护原始数据

    @property
    def size(self):
        """直方图大小的只读属性"""
        return self.__size

    @property
    def total_count(self):
        """数据点总数的属性"""
        return sum(self.__bins)

    @property
    def is_empty(self):
        """是否为空直方图的属性"""
        return self.total_count == 0

    # 特殊方法
    def __str__(self):
        """用户友好的字符串表示"""
        return f"Histogram(size={self.__size}, total_points={self.total_count})"

    def __repr__(self):
        """开发者的字符串表示，可用于重新创建对象"""
        return f"Histogram({self.__size})"

    def __len__(self):
        """返回直方图的bin数量"""
        return self.__size

    def __getitem__(self, index):
        """支持索引访问"""
        if not self._is_valid_index(index):
            raise IndexError(f"索引{index}超出范围[0, {self.__size - 1}]")
        return self.__bins[index]

    def __setitem__(self, index, value):
        """支持索引赋值（受保护的）"""
        if not self._is_valid_index(index):
            raise IndexError(f"索引{index}超出范围[0, {self.__size - 1}]")
        if not isinstance(value, int) or value < 0:
            raise ValueError("值必须是非负整数")

        self.__bins[index] = value

    def __contains__(self, value):
        """支持 in 运算符"""
        return self._is_valid_index(value) and self.__bins[value] > 0

    def __eq__(self, other):
        """比较两个直方图是否相等"""
        if not isinstance(other, Histogram):
            return False
        return self.__bins == other.__bins

    def __add__(self, other):
        """重载 + 运算符，合并两个直方图"""
        if not isinstance(other, Histogram):
            raise TypeError("只能合并EnhancedHistogram对象")

        max_size = max(self.__size, other.size)
        result = Histogram(max_size)

        # 合并数据
        for i in range(max_size):
            count1 = self.__bins[i] if i < self.__size else 0
            count2 = other[i] if i < other.size else 0
            result[i] = count1 + count2

        return result

    def __iadd__(self, other):
        """重载 += 运算符，原地合并"""
        if not isinstance(other, Histogram):
            raise TypeError("只能合并EnhancedHistogram对象")

        # 扩展大小
        if other.size > self.__size:
            self.__bins.extend([0] * (other.size - self.__size))
            self.__size = other.size

        # 合并数据
        for i in range(other.size):
            self.__bins[i] += other[i]

        return self

    # 私有方法
    def _is_valid_index(self, index):
        """验证索引是否有效（保护方法）"""
        if not isinstance(index, int):
            return False
        return 0 <= index < self.__size

    # 类方法
    @classmethod
    def from_list(cls, data_list):
        """从列表创建直方图对象"""
        if not data_list:
            raise ValueError("数据列表不能为空")

        max_val = max(data_list)
        hist = cls(max_val + 1)  # 创建足够大的直方图

        for value in data_list:
            if value < 0:
                raise ValueError("数据点不能为负数")
            hist.addDataPoint(value)

        return hist

    @classmethod
    def get_total_histograms(cls):
        """获取创建的直方图总数"""
        return cls.total_histograms

    @classmethod
    def get_version(cls):
        """获取版本信息"""
        return cls.version

    # 静态方法
    @staticmethod
    def validate_size(size):
        """验证直方图大小是否合法"""
        if not isinstance(size, int) or size <= 0:
            return False
        return True

    # 其他实用方法
    def get_frequency(self, value):
        """获取特定值的频率"""
        if not self._is_valid_index(value):
            return 0
        return self.__bins[value]

    def get_percentage(self, value):
        """获取特定值的百分比"""
        total = self.total_count
        if total == 0:
            return 0
        return (self.get_frequency(value) / total) * 100

    def reset(self):
        """重置直方图"""
        self.__bins = [0] * self.__size

    # 绘图方法
    def draw(self, max_bar_length=20):
        """绘制简单的文本直方图"""
        if self.is_empty:
            print("直方图为空")
            return

        max_freq = max(self.__bins)
        if max_freq == 0:
            print("没有数据点")
            return

        print("\n" + "=" * 50)
        print("直方图显示")
        print("=" * 50)

        for i in range(self.__size):
            freq = self.__bins[i]
            if freq > 0:
                # 计算条形长度
                bar_length = int((freq / max_freq) * max_bar_length)
                bar = '█' * bar_length
                percentage = self.get_percentage(i)
                print(f"{i:2d} | {bar:{max_bar_length}} | {freq:3d}次 ({percentage:5.1f}%)")

    # 特殊属性访问
    def show_special_attributes(self):
        """显示特殊属性信息"""
        print("\n=== 特殊属性信息 ===")
        print(f"类名: {self.__class__.__name__}")
        print(f"模块: {self.__class__.__module__}")
        print(f"基类: {self.__class__.__bases__}")
        print(f"MRO: {[cls.__name__ for cls in self.__class__.__mro__]}")
        print(f"实例字典: {self.__dict__}")
        print(f"类字典键: {list(self.__class__.__dict__.keys())}")


# 测试代码
if __name__ == "__main__":
    hist = Histogram(5)

    # 添加数据点
    hist.addDataPoint(2)
    hist.addDataPoint(3)
    hist.addDataPoint(2)
    hist.addDataPoint(4)
    hist.addDataPoint(1)
    hist.addDataPoint(2)

    print(f"直方图: {hist}")
    print(f"数据点总数: {hist.total_count}")

    # 测试属性访问
    print("\n=== 测试属性访问 ===")
    print(f"直方图数据: {hist.data}")
    print(f"直方图大小: {hist.size}")
    print(f"是否为空: {hist.is_empty}")

    # 测试特殊方法
    print("\n=== 测试特殊方法 ===")
    print(f"字符串表示: {hist}")
    print(f"开发表示: {repr(hist)}")
    print(f"长度(bin数量): {len(hist)}")
    print(f"索引2的值: {hist[2]}")
    print(f"值3是否在直方图中: {3 in hist}")
    print(f"值10是否在直方图中: {10 in hist}")  # 现在不会报错了

    # 测试索引赋值
    print("\n=== 测试索引赋值 ===")
    hist[0] = 2
    print(f"设置索引0后的数据: {hist.data}")

    # 测试类方法
    print("\n=== 测试类方法 ===")
    hist2 = Histogram.from_list([1, 2, 1, 3, 2, 4, 4, 4])
    print(f"从列表创建的直方图: {hist2}")
    print(f"总直方图数量: {Histogram.get_total_histograms()}")
    print(f"版本: {Histogram.get_version()}")

    # 测试运算符重载
    print("\n=== 测试运算符重载 ===")
    hist3 = hist + hist2
    print(f"合并后的直方图: {hist3}")
    print(f"合并后数据: {hist3.data}")

    # 测试其他方法
    print("\n=== 测试其他方法 ===")
    print(f"值2的频率: {hist.get_frequency(2)}")
    print(f"值2的百分比: {hist.get_percentage(2):.1f}%")

    # 测试绘图功能
    print("\n=== 测试绘图功能 ===")
    hist.draw()

    # 测试特殊属性
    print("\n=== 测试特殊属性 ===")
    hist.show_special_attributes()

    # 测试异常处理
    print("\n=== 测试异常处理 ===")
    try:
        hist.addDataPoint(10)  # 超出范围
    except ValueError as e:
        print(f"正确捕获错误: {e}")

    try:
        invalid_hist = Histogram(-5)  # 无效大小
    except ValueError as e:
        print(f"正确捕获错误: {e}")
